/***********************************************************

 The information in this document is proprietary
 to VeriSign and the VeriSign Product Development.
 It may not be used, reproduced or disclosed without
 the written approval of the General Manager of
 VeriSign Product Development.

 PRIVILEGED AND CONFIDENTIAL
 VERISIGN PROPRIETARY INFORMATION
 REGISTRY SENSITIVE INFORMATION

 Copyright (c) 2010 VeriSign, Inc.  All rights reserved.

 ***********************************************************/

package com.ordern.classification;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

/**
 * @author pdash
 */
public class TestDataDriver {
	/**
	 * @param classifier
	 * @param testDataBaseDir
	 * @param testDataFileName
	 * @param resultFileName
	 * @param boosterDirectory
	 *        Absolute path of directory that has booster domain files. Each file
	 *        name that matches LIKE %personal% will be counted as personal. Rest
	 *        all will be non-personal.
	 * @throws Exception
	 */
	public void runTest(CustomClassifier classifier, String testDataBaseDir,
			String testDataFileName, String resultFileName, String boosterDirectory )
			throws Exception {
		long startRead = System.currentTimeMillis();
		FileReader testFileReader = new FileReader(testDataBaseDir + "/"
				+ testDataFileName);
		List<Domain> domains = new InputParser().parseInput(testFileReader,
				testDataBaseDir);
		HashSet<String> personalSet =
				readPersonalDomainSet( testDataBaseDir, resultFileName );	
		long endRead = System.currentTimeMillis();
		long readTime = endRead - startRead;
		System.out.format("Read Time for %s domains is %d ms. ",
				domains.size(), readTime);

		List<Domain> boosterDomains = getBoosterDomains( boosterDirectory );
		
		List<Domain> trainSet = new ArrayList<Domain>();
		List<Domain> testSet = new ArrayList<Domain>();
		// randomCategorization( domains, personalSet, trainSet, testSet );
		fixedCategorization( domains, personalSet, trainSet, testSet );

		long startTrain = System.currentTimeMillis();
		classifier.train( boosterDomains, trainSet );
		long endTrain = System.currentTimeMillis();
		long trainTime = endTrain - startTrain;
		System.out.format("%nTrain Time for %s domains is %d ms. ", trainSet
				.size(), trainTime);

		long startTest = System.currentTimeMillis();
		classifier.test(testSet);
		long endTest = System.currentTimeMillis();
		long testTime = endTest - startTest;
		System.out.format("%nTest Time for %s domains is %d ms. %n%n", testSet
				.size(), testTime);

		printReportIntoConsole(trainSet, testSet, personalSet);
	}
	
	
	public static List<Domain> getBoosterDomains ( String boosterDirectory ) {
		List<Domain> boosterDomains = new ArrayList<Domain>();
		
		File f = new File( boosterDirectory );
		FilenameFilter filter = new FilenameFilter()
		{
			public boolean accept ( File f, String name ) {
				return !name.startsWith( "." );
			}
		};
		String[] children = f.list( filter );
		if ( children == null ) {
			// Either dir does not exist or is not a directory
			System.err.println( "Error reading booster files." );
		}
		else {
			for ( int i = 0; i < children.length; i++ ) {
				// Get filename of file or directory
				String filename = children[ i ];
				boolean isPesonal = false;
				if ( filename.toLowerCase().indexOf( "personal" ) != -1 ) {
					isPesonal = true;
				}
					try {
						Page page =
								new InputParser().getHTMLPageInfo( f.getAbsolutePath()
										+ File.separatorChar + filename );
						Domain boosterDomain = new Domain();
						boosterDomain.setTitle(page.getTitle());
						boosterDomain.setBody(page.getBody());
						boosterDomain.setMetaContent(page.getMetaContent());
						boosterDomain.setLocation( f.getAbsolutePath()
								+ File.separatorChar
								+ filename );
						boosterDomain.setDomainType( isPesonal ? DomainType.PERSONAL
								: DomainType.NOT_PERSONAL );
						boosterDomain.setName( filename + ".com" ); // :=)
						boosterDomains.add( boosterDomain );
					}
					catch ( Exception e ) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
				
				
			}
		}
		return boosterDomains;
	}
 
	private HashSet<String> readPersonalDomainSet ( String testDataBaseDir,
			String resultFileName ) throws FileNotFoundException, IOException {
		BufferedReader resultReader = new BufferedReader(new FileReader(
				testDataBaseDir + "/" + resultFileName));
		HashSet<String> personalSet = new HashSet<String>();
		String line = null;
		while ((line = resultReader.readLine()) != null) {
			if (line.lastIndexOf(":") > -1) {
				String category = line.substring(line.lastIndexOf(":") + 1);
				System.out.println("line is "+line);
				if (category.indexOf("not") < 0) {
					personalSet.add(line.substring(line.indexOf(":") + 1, line
							.lastIndexOf(":")));
				}
			}
		}
		return personalSet;
	}

	private void randomCategorization(List<Domain> domains,
			HashSet<String> personalSet, List<Domain> trainSet,
			List<Domain> testSet) {
		Random r = new Random();
		for (Domain domain : domains) {
			if (r.nextInt(10) < 8) {
				domain
						.setDomainType((personalSet.contains(domain.getName()) ? DomainType.PERSONAL
								: DomainType.NOT_PERSONAL));
				trainSet.add(domain);
			} else {
				// domain
				// .setDomainType( (personalSet.contains( domain.getName() ) ?
				// DomainType.PERSONAL
				// : DomainType.NOT_PERSONAL) );
				testSet.add(domain);
			}
		}
	}

	private void fixedCategorization(List<Domain> domains,
			HashSet<String> personalSet, List<Domain> trainSet,
			List<Domain> testSet) {
		int total = domains.size();
		int train = total * 90 / 100;
		Domain[] domainArray = domains.toArray(new Domain[2]);
		System.out.format(
				"%n Total domains is %s, train set is %s, and test set is %s",
				total, train, (total - train));

		for (int i = 0; i < train; i++) {
			domainArray[i]
					.setDomainType((personalSet.contains(domainArray[i]
							.getName()) ? DomainType.PERSONAL
							: DomainType.NOT_PERSONAL));
			trainSet.add(domainArray[i]);
		}
		for (int i = train; i < total; i++) {
			// domainArray[ i ].setDomainType( (personalSet.contains(
			// domainArray[ i ]
			// .getName() ) ? DomainType.PERSONAL : DomainType.NOT_PERSONAL) );
			testSet.add(domainArray[i]);
		}
	}

	void printReportIntoConsole(List<Domain> trainDomains,
			List<Domain> testDomains, Set<String> personalSet) {
		int successCount = 0;
		int personaltested = 0;
		int nonpersonaltested = 0;
		int actuallyPersonal = 0;
		int actuallyNonPersonal = 0;
		List<Domain> wronglyClassifiedPersonalDomains = new ArrayList<Domain>();
		List<Domain> wronglyClassifiedNonPersonalDomains = new ArrayList<Domain>();
		for (Domain domain : testDomains) {
			if (personalSet.contains(domain.getName())) {
				actuallyPersonal++;
				if (domain.getDomainType().equals(DomainType.PERSONAL)) {
					successCount++;
					personaltested++;
				} else {
					wronglyClassifiedPersonalDomains.add(domain);
				}
			} else {
				actuallyNonPersonal++;
				if (domain.getDomainType().equals(DomainType.NOT_PERSONAL)) {
					successCount++;
					nonpersonaltested++;
				} else {
					wronglyClassifiedNonPersonalDomains.add(domain);
				}
			}

		}

		int totalCount = trainDomains.size() + testDomains.size();
		System.out
				.println("Printing result ******************************************");
		System.out.println("Total Domains Used for Experiment: " + totalCount);
		System.out
				.format(
						"%nDomains put under test: %d {Personal: %d, Non-Personal: %d}. Non-Personal percentage = %.1f%%",
						testDomains.size(), actuallyPersonal,
						actuallyNonPersonal, actuallyNonPersonal * 100.0
								/ testDomains.size());
		System.out.format(
				"%nSuccessfullly categorized %d, In percentage: %.2f",
				successCount,
				((successCount * 1.0 / testDomains.size()) * 100.0));
		System.out
				.format(
						"%n%d Personal domains correctly identified out of %s, that is %.2f %%",
						personaltested, actuallyPersonal,
						(100.0 * personaltested) / actuallyPersonal);
		System.out
				.format(
						"%n%d NonPersonal domains correctly identified out of %s, that is %.2f %%",
						nonpersonaltested, actuallyNonPersonal,
						(100.0 * nonpersonaltested) / actuallyNonPersonal);
		System.out.println("\nWrongly Classified Personal Domains:>>> ");
		for (Domain domain : wronglyClassifiedPersonalDomains) {
			System.out.format("%n%s (comment='%s'):: %s", domain.getName(),
					domain.getClassifierComments(), domain.getLocation());
			System.out
					.format(
							"%n    Domain Metadata: %s%n    Domain Title: %s%n    Domain Classification: %s"
									+ "%n    Domain Body: %s", domain
									.getMetaContent(), domain.getTitle(),
							domain.getDomainType(), domain.getBody());
		}
		System.out.println("\nWrongly Classified Non Personal Domains:>>> ");
		for (Domain domain : wronglyClassifiedNonPersonalDomains) {
			System.out.format("%n%s (comment='%s'):: %s", domain.getName(),
					domain.getClassifierComments(), domain.getLocation());
			System.out
					.format(
							"%n    Domain Metadata: %s%n    Domain Title: %s%n    Domain Classification: %s"
									+ "%n    Domain Body: %s", domain
									.getMetaContent(), domain.getTitle(),
							domain.getDomainType(), domain.getBody());
		}
	}
}